﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using Crm2011.Framework.Core;
using Microsoft.Xrm.Client;
using Microsoft.Xrm.Client.Services;
using Microsoft.Xrm.Sdk.Client;
using Microsoft.Xrm.Sdk.Discovery;



namespace Crm2011.Framework.Connect
{
    public partial class ActiveDirectoryConnectionControl : UserControl, ICrmConnectionControl
    {
        public ActiveDirectoryConnectionControl()
        {
            InitializeComponent();
            _errorProviders = new ErrorProviderCollection(this);
        }



        private readonly ErrorProviderCollection _errorProviders;



        /// <summary>
        /// Gets the CRM connection string based on the controls.
        /// </summary>
        /// <returns></returns>
        CrmConnectionString ICrmConnectionControl.GetCrmConnectionString()
        {
            return new CrmConnectionString
                {
                    DiscoveryUrl = textDiscoveryUrl.Text,
                    Server = textWebApplicationUrl.Text,
                    UserId = textUsername.Text,
                    Password = (checkDefaultLogonCredentials.Checked) ? null : textPassword.Text,
                    Domain = textDomain.Text,
                    OrganizationUrl = textOrganizationServiceUrl.Text,
                    AuthenticationType = AuthenticationProviderType.ActiveDirectory,
                    OrganizationName = comboOrganizations.Text
                };
        }



        /// <summary>
        /// Sets the CRM connection string and populates the controls accordingly
        /// </summary>
        /// <param name="value">The value.</param>
        void ICrmConnectionControl.SetCrmConnectionString(CrmConnectionString value)
        {
            CrmConnectionString crmConnectionString = value ?? new CrmConnectionString();
            textDiscoveryUrl.Text = crmConnectionString.DiscoveryUrl ?? crmConnectionString.Server;
            textWebApplicationUrl.Text = crmConnectionString.Server;
            textOrganizationServiceUrl.Text = crmConnectionString.OrganizationUrl;

            textUsername.Text = crmConnectionString.UserId;
            textPassword.Text = crmConnectionString.Password;
            textDomain.Text = crmConnectionString.Domain;

            checkDefaultLogonCredentials.Checked = crmConnectionString.DefaultCredentials;

            // no organizations yet got from the server
            comboOrganizations.DropDownStyle = ComboBoxStyle.DropDown;
            comboOrganizations.Enabled = false;
            comboOrganizations.Text = (value != null && value.OrganizationName != null) ? value.OrganizationName : "";
        }



        private OrganizationDetail SelectedOrganization
        {
            get { return (comboOrganizations.SelectedItem != null) ? comboOrganizations.SelectedItem as OrganizationDetail : null; }
        }


        #region UI Event-Handlers


        private void btnConnectDiscoveryClick(object sender, EventArgs e)
        {
            _errorProviders.ClearAllErrors();
            comboOrganizations.Items.Clear();
            comboOrganizations.Enabled = false;
            comboOrganizations.DropDownStyle = ComboBoxStyle.DropDown;

            textWebApplicationUrl.Text = "";
            textOrganizationServiceUrl.Text = "";

            try
            {
                CrmConnectionString orgServiceConnectionString = ((ICrmConnectionControl)this).GetCrmConnectionString();
                orgServiceConnectionString.Server = orgServiceConnectionString.DiscoveryUrl;

                IEnumerable<OrganizationDetail> orgs = getOrganizations(orgServiceConnectionString); //clientCredentials, deviceCredentials);
                foreach (var organization in orgs)
                {
                    comboOrganizations.Items.Add(organization);
                }
                comboOrganizations.DisplayMember = "FriendlyName";
                comboOrganizations.DropDownStyle = ComboBoxStyle.DropDownList;
                comboOrganizations.Enabled = true;
                comboOrganizations.Focus();
            }
            catch (Exception exception)
            {
                _errorProviders.SetError(this.btnConnectDiscovery, exception.Message + (exception.InnerException != null ? Environment.NewLine + exception.InnerException.Message : ""));
            }
        }



        private void checkDefaultLogonCredentialsCheckedChanged(object sender, EventArgs e)
        {
            textDomain.Visible = !checkDefaultLogonCredentials.Checked;
            textUsername.Enabled = !checkDefaultLogonCredentials.Checked;
            textPassword.Enabled = !checkDefaultLogonCredentials.Checked;
        }



        //private void comboOrganizationsSelectedIndexChanged(object sender, EventArgs e)
        private void comboOrganizationsSelectionChanged(object sender, EventArgs e)
        {
            OrganizationDetail org = this.SelectedOrganization;
            textOrganizationServiceUrl.Text = org.Endpoints[EndpointType.OrganizationService];
            textWebApplicationUrl.Text = org.Endpoints[EndpointType.WebApplication];
        }


        #endregion


        IEnumerable<OrganizationDetail> getOrganizations(CrmConnectionString orgServiceCns) // ClientCredentials clientCredentials, ClientCredentials deviceCredentials)
        {
            CrmConnection crmConnection = CrmConnection.Parse(orgServiceCns.GetConnectionStringClearText());
            //using (var discoveryService = new DiscoveryServiceProxy( getDiscoveryServiceUrl(), null, clientCredentials, deviceCredentials))
            using (var discoveryService = new DiscoveryService(crmConnection))
            {
                var retrieveOrgsRequest = new RetrieveOrganizationsRequest
                {
                    AccessType = EndpointAccessType.Default,
                    Release = OrganizationRelease.Current
                };
                var response = (RetrieveOrganizationsResponse)discoveryService.Execute(retrieveOrgsRequest);
                return response.Details.Where(od => od.State == OrganizationState.Enabled);
            }
        }
    }
}